import { ActivatedRoute } from '@angular/router'
import { NzMessageService } from 'ng-zorro-antd'

import { PageService } from '@shared/services/page.service'
import { IBaseInfoColumn, HoverType } from '@shared/interfaces/baseInfo'
import { Observable, of } from 'rxjs'
import { getObjectValue, checkObjectEqual } from 'app/utils/helpers'

export abstract class DetailTabClass<T> {
  /* 拿到的 detail 信息 */
  data: T

  /** 原始数据，用于审核 */
  origData: T

  /*
   * 用这个来判断tab 是否true/ false. isEdits 架构 {'1': [false, false], '2': [false, false]}
   * 这里的 1 和 2 就是不同的Fieldset 每个 Feildset里有 >= 1的可更改Value
   */
  isEdits: { [field: string]: boolean[] } = {}
  columns: { [field: string]: IBaseInfoColumn[][] } = {}
  // Selected fields.
  field: string
  // Selected rowIndex
  rowIndex: number

  private hoveredColumn: IBaseInfoColumn | null

  abstract fields: { [key: string]: string }
  abstract onSubmit(): void
  abstract onCancel(): void
  abstract initialColumns(): void

  constructor(
    public pageService: PageService,
    public route: ActivatedRoute,
  ) {}

  getID(): string {
    return this.route.parent.snapshot.params['id']
  }

  setupIdForColumn(keys: { [key: string]: string }) {
    for (const key of Object.values(keys)) {
      for (const columns of this.columns[key]) {
        columns.filter(column => !column.operate).map((column, index) => (column.id = index))
      }
    }
  }

  makeFirstItemActive(): void {
    const id = this.columns[this.field][this.rowIndex][0].id
    this.activeItem(id, this.rowIndex)
  }

  setEdit(field: string, count: number) {
    // 这里创建每一个field里面展示的数据的编辑状态去false
    this.isEdits[field] = Array.from({ length: count }, _ => false)
  }

  // User select the element to edit, the item will be highlight in blue
  activeItem(id: number, rowIndex: number): void {
    // This to avoid highlight when user put edit in rowIndex 1 and they click on rowIndex 2.
    if (this.rowIndex !== rowIndex) {
      return
    }
    if (!this.isEdits[this.field][this.rowIndex]) return
    const targetColumn = this.columns[this.field][this.rowIndex].find(column => column.id === id)
    if (targetColumn) {
      if (this.hoveredColumn) this.disActiveColumn(this.hoveredColumn)
      this.activeColumn(targetColumn)
      this.hoveredColumn = targetColumn
    }
  }

  edit(k: string, rowIndex: number): void {
    if ((this.field && this.field !== k) || (this.rowIndex !== undefined && this.rowIndex !== rowIndex)) {
      this.cancel()
    }
    this.isEdits[k][rowIndex] = true
    this.field = k
    this.rowIndex = rowIndex
    this.makeFirstItemActive()
    this.pageService.triggerTabEdit(true)
  }

  checkEditValidation(): boolean {
    const columns = this.flatColumns()

    for (const col of columns) {
      if (col.validator && col.validator.isError) {
        return false
      }
    }

    return true
  }

  clearColumnsErrorTips() {
    const columns = this.flatColumns()

    for (const col of columns) {
      if (col.validator) {
        col.validator.currentErrorTip = ''
        col.validator.isError = false
      }
      if (!col.disEditable) {
        col.hover = HoverType.Normal
      }
    }
  }

  getDiffedColumns(columns: IBaseInfoColumn[]): Observable<IBaseInfoColumn[]> {
    columns.forEach(column => {
      const { index, operate } = column
      if (operate) return
      if (this.checkDiff(index)) {
        column.diff = true
      }
    })
    return of(columns)
  }

  /** 判断新旧两个值是否不同，如果diff，则返回 true */
  checkDiff(index: string): boolean {
    const origValue = getObjectValue(index, this.origData)
    const currentValue = getObjectValue(index, this.data)
    /** 如果是数组的情况, 当前，币种是数组 */
    if (origValue instanceof Array && currentValue instanceof Array) {
      return !checkObjectEqual(origValue, currentValue)
    }
    return origValue !== currentValue
  }

  private flatColumns(): IBaseInfoColumn[] {
    const columns: IBaseInfoColumn[] = []
    Object.values(this.columns).forEach(rows => {
      for (const row of rows) {
        columns.push(...row)
      }
    })

    return columns
  }

  private cancel(): void {
    this.isEdits[this.field][this.rowIndex] = false
    this.clearColumnsErrorTips()
    if (this.hoveredColumn) {
      this.disActiveColumn(this.hoveredColumn)
    }
    this.pageService.triggerTabEdit(false)
    this.onCancel()
  }

  private submit(): void {
    if (!this.checkEditValidation()) {
      return
    }
    this.clearColumnsErrorTips()

    this.isEdits[this.field][this.rowIndex] = false
    if (this.hoveredColumn) this.disActiveColumn(this.hoveredColumn)
    this.pageService.triggerTabEdit(false)
    this.onSubmit()
  }

  private activeColumn(column, target?: EventTarget) {
    /* 激活选项，有几步操作：
      1. 给外边框增加高亮
      2. 里面的 input 进入激活状态，并且鼠标移动到尾部
     */
    if (column.hover !== HoverType.Error) {
      column.hover = HoverType.Active
    }
  }

  private disActiveColumn(column: IBaseInfoColumn) {
    /*
      激活的反向操作
     */
    if (column.hover !== HoverType.Error) {
      column.hover = HoverType.Normal
    }
  }
}
